package com.travel.service.impl;

import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.travel.pojo.ScenicSpot;
import com.travel.pojo.UserOrder;
import com.travel.service.PdfService;
import com.travel.service.ScenicSpotService;
import com.travel.service.UserOrderService;
import com.travel.utils.SslUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @Description:
 * @Author: kohn
 * @CreateTime: 2024/7/14
 **/
@Service
@Slf4j
public class PdfTemplateServiceImpl implements PdfService {
    @Autowired
    private UserOrderService userOrderService;
    @Autowired
    private ScenicSpotService scenicSpotService;

    @Override
    public Document generateItextPdfDocument(OutputStream os, String orderId) throws Exception {
        String inputFileName = "pdf/contactTemplate.pdf"; // 合同模板
        PdfStamper ps = null; // 表单域 表单戳
        PdfReader reader = null; // pdf
        try {
            reader = new PdfReader(inputFileName);
            ps = new PdfStamper(reader, os);
            AcroFields form = ps.getAcroFields();
            BaseFont bf = BaseFont.createFont("pdf/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            form.addSubstitutionFont(bf);
            Map<String, String> data = genContactForm4OrderId(orderId);

            for (String key : data.keySet()) {
                if (key.equals("visitor_signature")) {
                    int pageno = form.getFieldPositions("visitor_signature").get(0).page;
                    Rectangle signrect = form.getFieldPositions("visitor_signature").get(0).position;
                    float x = signrect.getLeft();
                    float y = signrect.getBottom();
                    Image img = null;
                    try {
                        URL url = new URL(data.get("visitor_signature"));
                        SslUtils.ignoreSsl();
                        log.info("Signature URL: " + url);
                        img = Image.getInstance(url);
                    } catch (MalformedURLException | FileNotFoundException e) {
                        img = Image.getInstance(new ClassPathResource("static/images/defaultSignature.png").getURL());
                    }
                    PdfContentByte under = ps.getOverContent(pageno);
                    img.scaleToFit(signrect.getWidth(), signrect.getHeight());
                    img.setAbsolutePosition(x, y);
                    under.addImage(img);
                    continue;
                }
                form.setFieldProperty(key, "textsize", 12f, null);
                form.setFieldProperty(key, "textfont", bf, null);
                Object value = data.get(key);
                form.setField(key, value == null ? "" : value.toString());
            }
            ps.setFormFlattening(true);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ps != null) ps.close();
            if (reader != null) reader.close();
        }
        return null;
    }

    public byte[] generatePdfAndConvertToLongImage(String userId) throws Exception {
        File tempFile = File.createTempFile("generated", ".pdf");
        try (OutputStream outputStream = new FileOutputStream(tempFile)) {
            generateItextPdfDocument(outputStream, userId);
        }

        try (PDDocument document = PDDocument.load(tempFile)) {
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

            int totalHeight = 0;
            int maxWidth = 0;
            BufferedImage[] images = new BufferedImage[document.getNumberOfPages()];
            Future<BufferedImage>[] futures = new Future[document.getNumberOfPages()];

            for (int page = 0; page < document.getNumberOfPages(); page++) {
                final int currentPage = page;
                futures[page] = executor.submit(() -> pdfRenderer.renderImageWithDPI(currentPage, 150, ImageType.RGB));
            }

            for (int page = 0; page < futures.length; page++) {
                BufferedImage bufferedImage = futures[page].get();
                images[page] = bufferedImage;
                totalHeight += bufferedImage.getHeight();
                maxWidth = Math.max(maxWidth, bufferedImage.getWidth());
            }

            executor.shutdown();

            BufferedImage longImage = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = longImage.createGraphics();
            int currentHeight = 0;
            for (BufferedImage image : images) {
                g2d.drawImage(image, 0, currentHeight, null);
                currentHeight += image.getHeight();
            }
            g2d.dispose();

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(longImage, "png", byteArrayOutputStream);
            return byteArrayOutputStream.toByteArray();
        } finally {
            tempFile.delete();
        }
    }

    private Map<String, String> genContactForm4OrderId(String orderId) {
        Map<String, String> map = new HashMap<>();
        UserOrder userOrder = userOrderService.getById(orderId);
        map.put("visitor_name", userOrder.getUserName());
        map.put("phone_number", userOrder.getLinkTel());
        map.put("hotel_address", userOrder.getHotelAddress());
        map.put("backup_phone", userOrder.getLinkTelBk());
        map.put("audlt_num", String.valueOf(userOrder.getAdultCount()));
        map.put("oldandstudent_num", String.valueOf(userOrder.getOldStuCount()));
        map.put("child_under1.3_num", String.valueOf(userOrder.getChildrenCount()));
        String[] productIdList = userOrder.getProductId().split(",");
        for (int i = 0; i < productIdList.length && i < 6; i++) {
            ScenicSpot scenicSpot = scenicSpotService.getById(productIdList[i]);
            if (scenicSpot != null) {
                map.put("travel_name_" + (i + 1), scenicSpot.getSpotName());
                map.put("travel_introduce_" + (i + 1), scenicSpot.getSpotIntro());
            }
        }
        map.put("total_cost", String.valueOf(userOrder.getFee()));
        map.put("visitor_identity", userOrder.getIcCode());

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDate orderDate = LocalDate.parse(userOrder.getAddTime(), dateTimeFormatter);
        map.put("year", String.valueOf(orderDate.getYear()));
        map.put("month", String.valueOf(orderDate.getMonthValue()));
        map.put("day", String.valueOf(orderDate.getDayOfMonth()));
        map.put("visitor_signature", userOrder.getASignmentImg());
        return map;
    }

}
